Popular Searches
Popular Course Categories
Popular Courses

Displaying Toast Messages, Snackbars, and Dialogs

Displaying Toast Messages, Snackbars, and Dialogs

User Interaction, Forms, and Navigation

Displaying Toast Messages, Snackbars, and Dialogs in Android Using Jetpack Compose

Course: Android App Development

Topic: Displaying Toast Messages, Snackbars, and Dialogs

Course Link: Android App Development Course

Demo Registration: Register for a Course Demo

JustAcademy Homepage: Visit JustAcademy


1. Introduction

Android applications need to communicate with users when an action succeeds, an error occurs, data is saved, or confirmation is required. Jetpack Compose provides several ways to display these messages, including Toast messages, Snackbars, and Dialogs.

These components serve different purposes. A Toast displays a brief message, a Snackbar provides temporary feedback and can include an action, and a Dialog presents information or requests a decision before the user continues.

For example, a shopping application may show a Toast when an item is added to a cart, a Snackbar with an Undo action when an item is removed, and a Dialog asking the user to confirm an order cancellation.

2. Learning Objectives

  • Understand Toast messages, Snackbars, and Dialogs.
  • Display Toast messages using Android APIs in Jetpack Compose.
  • Implement Snackbars with Scaffold and SnackbarHostState.
  • Add actions such as Undo and Retry to Snackbars.
  • Create AlertDialog components for confirmations and alerts.
  • Manage dialog visibility using Compose state.
  • Handle user interactions and dismissal events.
  • Choose the appropriate notification component for different situations.
  • Apply accessibility and UI design best practices.

3. Understanding Toast Messages

A Toast is a small, temporary message displayed to provide brief feedback. It does not require the user to interact with it and disappears automatically after a short period.

Common uses of Toast messages

  • Informing users that an action has completed.
  • Displaying a brief status message.
  • Confirming that a simple operation was triggered.
  • Providing lightweight feedback when no additional action is necessary.

Advantages

  • Easy to implement.
  • Does not require confirmation from the user.
  • Useful for short, non-critical status messages.

Limitations

  • Disappears automatically.
  • Does not provide a built-in action button.
  • Is unsuitable for important messages that users must read or confirm.
  • Offers less control over placement and presentation than an in-layout Compose component.

4. Displaying a Toast in Jetpack Compose

In Jetpack Compose, the current Android context can be obtained using LocalContext.current. The context is passed to Toast.makeText() to create and display a Toast.

import android.widget.Toast
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext

@Composable
fun ToastExample() {
    val context = LocalContext.current

    Button(
        onClick = {
            Toast.makeText(
                context,
                "Profile saved successfully!",
                Toast.LENGTH_SHORT
            ).show()
        }
    ) {
        Text("Save Profile")
    }
}

Explanation

  1. LocalContext.current provides the current Android context.
  2. Button creates a clickable button.
  3. Toast.makeText() creates a Toast with the context, message, and duration.
  4. Toast.LENGTH_SHORT specifies a short display duration.
  5. .show() displays the Toast to the user.

5. Toast Duration

Android provides standard Toast duration constants for common use cases.

Constant Purpose Example
Toast.LENGTH_SHORT Displays the message for a short period. Settings saved
Toast.LENGTH_LONG Displays the message for a longer standard period. Operation completed

The exact display duration is controlled by Android and can be affected by accessibility settings. These constants do not allow an arbitrary custom duration.

Example using a longer Toast

Toast.makeText(
    context,
    "Your changes have been submitted successfully.",
    Toast.LENGTH_LONG
).show()

Use longer messages carefully. If the information is important, consider a Snackbar, persistent on-screen message, or Dialog instead of relying on a Toast that disappears.

6. Creating a Reusable Toast Function

If an application displays Toast messages in several places, a helper function can reduce repeated code. For a small example, the helper can accept a context and message.

import android.content.Context
import android.widget.Toast

fun showToast(
    context: Context,
    message: String
) {
    Toast.makeText(
        context,
        message,
        Toast.LENGTH_SHORT
    ).show()
}

Usage inside a composable:

@Composable
fun LoginButtonExample() {
    val context = LocalContext.current

    Button(
        onClick = {
            showToast(
                context,
                "Login button clicked"
            )
        }
    ) {
        Text("Login")
    }
}

For larger applications, keep notification logic organized and avoid creating unnecessary abstractions for a simple one-off message. Use a Snackbar when users need an action or when feedback should be integrated into the current screen.

7. Understanding Snackbars

A Snackbar is a temporary message usually displayed near the bottom of the screen. It provides feedback without blocking the current task. Unlike a basic Toast, a Snackbar can include an action such as Undo or Retry.

In Jetpack Compose Material 3, Snackbars are commonly managed through SnackbarHostState and displayed using SnackbarHost, often within a Scaffold.

Common uses of Snackbars

  • Confirming that data was saved.
  • Showing that a record was deleted.
  • Offering an Undo action after a reversible operation.
  • Informing users about a temporary network problem.
  • Providing a Retry action after a recoverable failure.

Toast vs. Snackbar

Feature Toast Snackbar
Typical presentation Brief system message Temporary message integrated into the app UI
Action button No built-in action button Can provide an action
Compose integration Uses Android Toast APIs Uses Compose Material components
Best use Simple, non-critical feedback Contextual feedback and optional actions
Example “Copied” “Item deleted” with “Undo”

8. Creating a Basic Snackbar

To display a Snackbar, create a SnackbarHostState, place a SnackbarHost in the screen layout, and call showSnackbar() in a coroutine. Because showSnackbar() is a suspending function, it must be called from a coroutine or another suspend function.

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch

@Composable
fun BasicSnackbarExample() {
    val snackbarHostState = remember {
        SnackbarHostState()
    }

    val scope = rememberCoroutineScope()

    Scaffold(
        snackbarHost = {
            SnackbarHost(
                hostState = snackbarHostState
            )
        }
    ) { innerPadding ->
        Column(
            modifier = Modifier
                .padding(innerPadding)
                .padding(16.dp)
        ) {
            Button(
                onClick = {
                    scope.launch {
                        snackbarHostState.showSnackbar(
                            "Your settings have been saved."
                        )
                    }
                }
            ) {
                Text("Save Settings")
            }
        }
    }
}

Explanation

  • SnackbarHostState stores and manages the Snackbar display state.
  • remember keeps the state object across recompositions.
  • rememberCoroutineScope() provides a coroutine scope associated with the composable's lifecycle.
  • Scaffold provides a standard screen structure.
  • SnackbarHost displays the Snackbar managed by the state object.
  • showSnackbar() displays the message and suspends until the Snackbar finishes.

9. Creating a Snackbar with an Action Button

Snackbars can offer an action related to the message. A common example is allowing users to undo a deletion. The action result indicates whether the action was performed or the Snackbar was dismissed.

import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarResult

scope.launch {
    val result = snackbarHostState.showSnackbar(
        message = "Item deleted",
        actionLabel = "Undo",
        withDismissAction = true,
        duration = SnackbarDuration.Long
    )

    when (result) {
        SnackbarResult.ActionPerformed -> {
            // Restore the deleted item.
        }

        SnackbarResult.Dismissed -> {
            // Snackbar ended without the action.
        }
    }
}

This code belongs inside a coroutine, such as the one launched by a button's click handler. The actual deletion and restoration logic must be implemented by the application.

Important Snackbar properties

Property or API Purpose
message Sets the message displayed in the Snackbar.
actionLabel Provides text for an optional action button.
duration Controls the standard duration behavior.
withDismissAction Requests a visible dismiss action where supported.
SnackbarResult.ActionPerformed Indicates that the action was selected.
SnackbarResult.Dismissed Indicates that the Snackbar was dismissed or timed out without the action.

10. Understanding Snackbar Duration

Material 3 provides standard Snackbar duration options. Choose a duration that gives users enough time to read the message and interact when necessary.

  • SnackbarDuration.Short — suitable for brief messages.
  • SnackbarDuration.Long — provides more time for longer messages.
  • SnackbarDuration.Indefinite — keeps the Snackbar visible until it is acted on or dismissed.

Use indefinite duration sparingly. A Snackbar with an action should give users a reasonable opportunity to act, and accessibility settings may affect timing behavior. Avoid putting critical information exclusively in a temporary message.

11. Understanding Dialogs

A Dialog is a UI element displayed above the current screen. It is commonly used to communicate important information, request confirmation, or collect a small amount of input before allowing the user to continue.

Common uses of Dialogs

  • Confirming deletion of a record.
  • Asking the user to confirm logout.
  • Explaining an important error.
  • Requesting a decision before cancelling an order.
  • Presenting a small form or a choice that needs focused attention.

Types of dialog-related components

Component Purpose
AlertDialog A standard dialog with a title, text, and action buttons.
Dialog A more flexible dialog container for custom content.
BasicAlertDialog A lower-level alert-dialog API available in supported Material 3 versions for more customized content.

For most simple confirmation dialogs, AlertDialog is a convenient starting point.

12. Creating an AlertDialog in Jetpack Compose

Compose dialogs are generally shown conditionally. A state variable controls whether the dialog is visible, and button callbacks update that state.

import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

@Composable
fun BasicDialogExample() {
    var showDialog by remember {
        mutableStateOf(false)
    }

    Button(
        onClick = {
            showDialog = true
        }
    ) {
        Text("Show Dialog")
    }

    if (showDialog) {
        AlertDialog(
            onDismissRequest = {
                showDialog = false
            },
            title = {
                Text("Confirmation")
            },
            text = {
                Text("Do you want to continue?")
            },
            confirmButton = {
                TextButton(
                    onClick = {
                        showDialog = false
                    }
                ) {
                    Text("Continue")
                }
            },
            dismissButton = {
                TextButton(
                    onClick = {
                        showDialog = false
                    }
                ) {
                    Text("Cancel")
                }
            }
        )
    }
}

Explanation

  1. showDialog stores the visibility state.
  2. Pressing the button sets showDialog to true.
  3. The conditional block displays the AlertDialog when the state is true.
  4. onDismissRequest handles dismissal requests, such as tapping outside the dialog or pressing Back when permitted.
  5. confirmButton defines the primary action.
  6. dismissButton defines an alternative action, such as Cancel.
  7. Each action updates the state to hide the dialog.

In a real application, the Continue action should also perform the intended operation. Dismissing a dialog alone does not automatically save data, delete a record, or complete a transaction.

13. Creating a Delete Confirmation Dialog

Before deleting important data, an application can ask the user to confirm the action. This helps prevent accidental deletion.

@Composable
fun DeleteConfirmationExample(
    onDeleteConfirmed: () -> Unit
) {
    var showDialog by remember {
        mutableStateOf(false)
    }

    Button(
        onClick = {
            showDialog = true
        }
    ) {
        Text("Delete Item")
    }

    if (showDialog) {
        AlertDialog(
            onDismissRequest = {
                showDialog = false
            },
            title = {
                Text("Delete item?")
            },
            text = {
                Text(
                    "This action may permanently remove the item. " +
                    "Do you want to continue?"
                )
            },
            confirmButton = {
                TextButton(
                    onClick = {
                        onDeleteConfirmed()
                        showDialog = false
                    }
                ) {
                    Text("Delete")
                }
            },
            dismissButton = {
                TextButton(
                    onClick = {
                        showDialog = false
                    }
                ) {
                    Text("Cancel")
                }
            }
        )
    }
}

The onDeleteConfirmed callback lets the parent component handle the deletion. In a production application, the parent should also manage loading, errors, and the final result of the operation.

14. Creating a Custom Dialog

When a standard AlertDialog does not provide the layout required by an application, the Compose Dialog component allows developers to design custom content.

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog

@Composable
fun CustomDialogExample(
    onDismiss: () -> Unit
) {
    Dialog(
        onDismissRequest = onDismiss
    ) {
        Card {
            Column(
                modifier = Modifier.padding(24.dp)
            ) {
                Text("Welcome!")
                Text(
                    "Explore your courses and track your progress."
                )

                Button(
                    onClick = onDismiss
                ) {
                    Text("Got it")
                }
            }
        }
    }
}

Show this composable conditionally from a parent when a Boolean state indicates that the dialog should be visible. The caller must provide the dismissal behavior and manage the visibility state.

15. Displaying Toasts, Snackbars, and Dialogs in One Screen

The following example combines all three notification styles in one Compose screen. It demonstrates when each component can be triggered and how its state or API is managed.

import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch

@Composable
fun NotificationDemoScreen() {
    val context = LocalContext.current

    val snackbarHostState = remember {
        SnackbarHostState()
    }

    val scope = rememberCoroutineScope()

    var showDialog by remember {
        mutableStateOf(false)
    }

    Scaffold(
        snackbarHost = {
            SnackbarHost(
                hostState = snackbarHostState
            )
        }
    ) { innerPadding ->
        Column(
            modifier = Modifier
                .padding(innerPadding)
                .padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(12.dp)
        ) {
            Button(
                onClick = {
                    Toast.makeText(
                        context,
                        "Action completed",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            ) {
                Text("Show Toast")
            }

            Button(
                onClick = {
                    scope.launch {
                        snackbarHostState.showSnackbar(
                            "Changes saved successfully"
                        )
                    }
                }
            ) {
                Text("Show Snackbar")
            }

            Button(
                onClick = {
                    showDialog = true
                }
            ) {
                Text("Show Dialog")
            }
        }
    }

    if (showDialog) {
        AlertDialog(
            onDismissRequest = {
                showDialog = false
            },
            title = {
                Text("Important Information")
            },
            text = {
                Text(
                    "Review the information before continuing."
                )
            },
            confirmButton = {
                TextButton(
                    onClick = {
                        showDialog = false
                    }
                ) {
                    Text("OK")
                }
            }
        )
    }
}

This example uses Material 3 Compose components. Ensure the project includes compatible Compose Material 3 dependencies and the appropriate imports. The screen demonstrates notification display only; actual business operations should be implemented separately.

16. Choosing the Right Notification Component

Situation Recommended Component Reason
Brief confirmation that copying succeeded Toast or Snackbar Simple status feedback.
Record deleted with an Undo option Snackbar Offers a related action.
Confirmation before deleting important data AlertDialog Requests a deliberate decision.
Recoverable network failure with Retry Snackbar or an inline error message Provides feedback and a recovery path.
Critical error requiring a decision Dialog, when interruption is justified Brings focused attention to the issue.
Persistent form validation error Inline error text Keeps the problem visible near the relevant field.
Background task that takes a long time Progress indicator or persistent status UI Temporary pop-ups are not suitable for ongoing progress.

17. Accessibility and User Experience Best Practices

  • Use short, clear, actionable messages.
  • Do not rely exclusively on Toasts for important information.
  • Use a Snackbar action only when it provides a meaningful next step.
  • Use Dialogs sparingly because they interrupt the current workflow.
  • Give confirmation dialogs descriptive titles and clear action labels.
  • Avoid ambiguous buttons such as “Yes” and “No” when labels like “Delete” and “Keep item” communicate the result more clearly.
  • Ensure text can scale and remains readable.
  • Keep focus and dismissal behavior appropriate when dialogs open and close.
  • Display persistent validation errors near the related input instead of repeatedly showing pop-ups.
  • Use string resources for production messages so they can be localized.

18. Common Errors and Troubleshooting

Problem Possible Cause Solution
Toast does not appear Missing context or .show(). Use LocalContext.current and call .show().
Snackbar does not appear No SnackbarHost or the wrong host state is being used. Ensure the Scaffold contains a SnackbarHost using the same SnackbarHostState.
Compile error with showSnackbar Called outside a coroutine. Call it inside scope.launch or another suspend function.
Dialog remains visible Visibility state is not updated. Set the state to false in the relevant callbacks.
Dialog closes but action does not happen Only the visibility state was changed. Call the required application callback before dismissing the dialog.
Dialog appears repeatedly Visibility state is initialized or updated incorrectly. Use remembered state or an appropriate state holder and review recomposition logic.
Snackbar action has no effect The action result is not handled. Inspect SnackbarResult.ActionPerformed and implement the action.
Important message disappears too quickly A transient notification is being used for critical information. Use inline status text, an appropriate persistent UI element, or a dialog when confirmation is required.

19. Practical Exercise

Project: Build a simple Course Management screen using Jetpack Compose.

Requirements

  1. Create a button that displays a Toast confirming that a course was selected.
  2. Create a Save button that displays a Snackbar after saving.
  3. Add an Undo action to a Snackbar when a course is removed.
  4. Display an AlertDialog before permanently deleting a course.
  5. Use Compose state to manage dialog visibility.
  6. Handle confirm and cancel actions separately.
  7. Test all messages on an Android emulator or device.
  8. Ensure important errors remain visible when appropriate.

Expected result

The application should provide clear feedback for simple events, use Snackbars for contextual messages and actions, and use Dialogs when users must make a deliberate decision.

20. Interview Questions and Answers

Q1. What is a Toast in Android?

Answer: A Toast is a temporary message used to provide brief feedback without requiring user interaction.

Q2. What is a Snackbar?

Answer: A Snackbar is a temporary message displayed within the application UI. It can include an optional action such as Undo or Retry.

Q3. What is the main difference between a Toast and a Snackbar?

Answer: A Toast is a simple system message, while a Snackbar is integrated with the app layout and can offer an action button.

Q4. What is an AlertDialog?

Answer: An AlertDialog is a dialog component that displays information or asks the user to confirm or cancel an action.

Q5. Why is LocalContext used with Toast messages?

Answer: It provides access to the current Android context required by Toast.makeText().

Q6. What is SnackbarHostState?

Answer: It manages Snackbar display state and provides the showSnackbar() function.

Q7. Why does showSnackbar require a coroutine?

Answer: It is a suspending function that waits for the Snackbar to finish, so it must be called from a coroutine or another suspend function.

Q8. How do you control dialog visibility in Compose?

Answer: Use a state variable, commonly created with remember { mutableStateOf(false) }, and display the dialog conditionally.

Q9. What does onDismissRequest do?

Answer: It handles requests to dismiss a dialog, allowing the application to update its visibility state or respond appropriately.

Q10. When should a Dialog be preferred over a Snackbar?

Answer: Use a Dialog when important information or a decision requires focused attention, such as confirming a destructive action. Use Snackbars for brief contextual feedback.

21. Quick Revision

  • Toast: simple, temporary status message.
  • Snackbar: temporary in-app feedback with an optional action.
  • Dialog: focused UI for information or user decisions.
  • LocalContext.current provides the context for Android Toast APIs.
  • SnackbarHostState manages Snackbar display.
  • rememberCoroutineScope() can launch a coroutine to call showSnackbar().
  • AlertDialog provides a standard dialog with title, text, and action buttons.
  • Compose state controls whether a dialog is visible.
  • Callbacks connect notification UI to application behavior.
  • Use the least disruptive component that clearly communicates the message.

22. Conclusion

Toast messages, Snackbars, and Dialogs are important tools for communicating with users in Android applications. Toasts provide brief feedback, Snackbars provide contextual messages and optional actions, and Dialogs are useful when information or a decision requires focused attention.

With Jetpack Compose, developers can manage these interactions using composable functions, state, callbacks, SnackbarHostState, and Material 3 components. Choosing the right notification pattern helps create Android applications that are clear, responsive, accessible, and easier to maintain.

Continue learning: Explore the Android App Development Course | Register for a Course Demo | Visit JustAcademy

Previous Next
whatsapp